package tools;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class XmlParserUtility {

	/**
	 * Reads an XML file, parses it and generates a Document Object Model Object
	 * for further Processing.
	 * 
	 * @param FileName
	 *            - The FileName of the input XML file*
	 * @return dom - The Document Object Model generated after parsing the XML
	 *         file. To be used for other xml related operations.
	 * 
	 */
	public Document ReadXMLFile(String FileName) {

		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		Document dom = null;
		try {

			// Using factory get an instance of document builder
			DocumentBuilder db = dbf.newDocumentBuilder();

			// parse using builder to get DOM representation of the XML file
			dom = db.parse(FileName);
			dom.getDocumentElement().normalize();

			System.out.println("Root element :"
					+ dom.getDocumentElement().getNodeName());

			return dom;

		} catch (ParserConfigurationException pce) {
			System.out
					.println("\nThe XML file was not properly written, please try again: "
							+ pce);
		} catch (SAXException se) {
			System.out
					.println("\nThe XML file is not in the proper format, please try again: "
							+ se);
			;
		} catch (IOException ioe) {
			System.out.println("\nError reading from file " + FileName
					+ ", please try again: " + ioe);
		}
		return dom;

	}

	/**
	 * Extracts all the Element of an XMLDocument by Parsing it and thereafter
	 * Generates an ArrayList of all the elements.
	 * 
	 * @param TagName
	 * @param dom
	 * @return
	 */
	public ArrayList<?> ParseXMLDocument(String TagName, Document dom) {
		// get the root element
		Element docEle = dom.getDocumentElement();

		// get a node-list of elements
		// NodeList n1=docEle.getChildNodes();
		NodeList nl = docEle.getElementsByTagName(TagName);
		// An Array List of Elements of each Node
		ArrayList<Element> ElementList = new ArrayList<Element>();

		if (nl != null && nl.getLength() > 0) {
			for (int i = 0; i < nl.getLength(); i++) {
				// Node nNode = nList.item(i);
				// if (nNode.getNodeType() == Node.ELEMENT_NODE){

				// get the elements of the tagName
				Element el = (Element) nl.item(i);

				// add it to list
				ElementList.add(el);
			}
		}
		return ElementList;

	}

	/**
	 * It takes a xml element and the tag name, look for the tag and get the
	 * text content<br />
	 * i.e for example <Dictionary><en>Authority</en></Dictionary> xml snippet
	 * if<br />
	 * the Element points to Dictionary node and tagName is 'en' It will return
	 * Authority
	 * 
	 * @param element
	 *            The element of the XML Node eg. a record
	 * @param tagName
	 *            The tag name of the information required.
	 * @return textVal the textual/String value of the element with the specific
	 *         tag.
	 */

	public String getTextValue(Element element, String tagName) {
		String textVal = null;
		NodeList nl = element.getElementsByTagName(tagName);
		if (nl != null && nl.getLength() > 0) {
			Element el = (Element) nl.item(0);
			textVal = el.getFirstChild().getNodeValue();
		}

		return textVal;
	}

	/**
	 * Gets the Interger Value of the Element
	 * 
	 * @param ele
	 * @param tagName
	 * @return
	 * @throws NumberFormatException
	 */
	int getIntValue(Element ele, String tagName) throws NumberFormatException {

		return Integer.parseInt(getTextValue(ele, tagName));
	}

	/***
	 * Modifies and Updates the Attributes values of an XML Structure <br />
	 * For Example:
	 * 
	 * <pre>
	 * <Word>
	 *      <Index>1</Index>
	 *     <en>Play</en>
	 *      <fr>Jouer</fr>
	 *      <WordCount>120</WordCount>
	 *     </Word>
	 * </pre>
	 * 
	 * To update wordcount to 121 we need to Modify the XML element with
	 * tagName: "Word",tag ID: "WordCount" with the Word Count:121<br />
	 * Such that : ModifyXMLElement("BilingueDict.xml","Word","WordCount","121"
	 * );
	 * 
	 * @param FileName
	 * @param TagName
	 * @param TagID
	 * @param TextContent
	 */
	public void ModifyXMLElement(String FileName, String TagName, String TagID,
			String TextContent) {

		try {

			DocumentBuilderFactory docFactory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
			Document doc = docBuilder.parse(FileName);

			// Get the Node element by tag name directly
			// eg.
			// <Word><Index>1</Index><en>Authentication</en><fr>Authentification</fr></Word>
			// Get the elements in Word
			Node nodeElements = doc.getElementsByTagName(TagName).item(0);

			// update staff attribute
			NamedNodeMap attr = nodeElements.getAttributes();
			Node nodeAttr = attr.getNamedItem(TagID);
			nodeAttr.setTextContent(TextContent);

			// write the content into xml file
			TransformerFactory transformerFactory = TransformerFactory
					.newInstance();
			Transformer transformer = transformerFactory.newTransformer();
			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(new File(FileName));
			transformer.transform(source, result);

			System.out.println("XML File UPdate Successfully");

		} catch (ParserConfigurationException pce) {
			pce.printStackTrace();
		} catch (TransformerException tfe) {
			tfe.printStackTrace();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} catch (SAXException sae) {
			sae.printStackTrace();
		}
	}
}
